﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Animation;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Dynamics.Joints;
using Enemies;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
using AI;
using Microsoft.Xna.Framework.Graphics;
using MapLibrary.Players.Skills;
using MapLibrary.Particles;
using MapLibrary.Enemies;

namespace MapLibrary.Players.Abilities
{


    namespace MapLibrary.Players.Skills
    {
        class Hook : Sprite
        {
            private const int MAX_LENGTH = 650;


            public int TimeToLive { get; set; }

            public Texture2D ropeTexture;

            private float length;
            private Vector2 direction;
            private Rectangle ropeSource;
            public HookShot hookShot { get; set; }
            public SliderJoint Joint { get; set; }
            private bool attached;
            public bool AttachedToWall { get; set; }
            public HookableObject HookedObject { get; set; }
            private bool retracting;

            public Hook()
            {
                MAX_VELOCITY_X = ConvertUnits.ToSimUnits(1000);
                MAX_VELOCITY_Y = ConvertUnits.ToSimUnits(1000);
                this.Controller.MaxLinearVelocityX = MAX_VELOCITY_X;
                this.Controller.MaxLinearVelocityY = MAX_VELOCITY_Y;

                attached = false;
                length = 0;
                retracting = false;

                ropeSource = new Rectangle(0,0,0,5);
            }

            public override void Update()
            {
                base.Update();
                if (hookShot == null)
                {
                    return;
                }
                TimeToLive--;
                if (TimeToLive < 0 || (attached && length < 75))
                {
                    hookShot.Deactivate();
                    if (HookedObject != null)
                    {
                        HookedObject.IsHooked = false;
                        HookedObject = null;
                    }
                    World.CurrentLevel.AddBodyToRemove(this);
                }
                else if (length >= MAX_LENGTH && !attached && !retracting)
                {
                    retracting = true;
                    Body.IsSensor = true;
                }
                else if(retracting && length < 50)
                {
                    if (HookedObject != null)
                    {
                        HookedObject.IsHooked = false;
                        HookedObject = null;
                    }
                    hookShot.Deactivate();
                    World.CurrentLevel.AddBodyToRemove(this);
                }
                else if (retracting)
                {
                    Vector2 dir = World.CurrentLevel.Player.GetPosition() - GetPosition();
                    dir.Normalize();
                    Vector2 vel;

                    if (!attached)
                    {
                        vel = dir * 10.0f;
                    }
                    else
                    {
                        vel = dir * 2.0f;
                        vel.Y = 0.0f;
                    }
                    Body.LinearVelocity = vel;

                    float angle = (float)Math.Atan2(dir.Y, dir.X);
                    Rotation = angle + MathHelper.ToRadians(180);
                }
            }

            public void Remove()
            {
                if (HookedObject != null)
                {
                    HookedObject.IsHooked = false;
                    HookedObject = null;
                }
                World.CurrentLevel.AddBodyToRemove(this);
            }

            public override bool MyOnCollision(Fixture f1, Fixture f2, Contact contact)
            {
                Sprite s1 = f1.Body.UserData as Sprite;
                Sprite s2 = f2.Body.UserData as Sprite;

                if (Joint != null)
                {
                    return false;
                }

                if (retracting)
                {
                    return false;
                }

                if (s2 == null)
                {
                    LevelCollisionRegion lcr = f2.Body.UserData as LevelCollisionRegion;
                    if (lcr != null)
                    {
                        Vector2 anchorB = f1.Body.Position - lcr.Body.Position;
                        Joint = JointFactory.CreateSliderJoint(World.PhysicsWorld, s1.Body, lcr.Body, Vector2.Zero, anchorB, 0.0f, 0.0f);
                        Joint.DampingRatio = 1.0f;
                        hookShot.HasAttached = true;
                        attached = true;
                        AttachedToWall = true;
                        return true;
                    }
                }
                else
                {
                    HookableObject ho = s2 as HookableObject;
                    if (ho != null)
                    {
                        ho.IsHooked = true;
                        HookedObject = ho;
                        Vector2 anchorB = f1.Body.Position - s2.Body.Position;
                        Joint = JointFactory.CreateSliderJoint(World.PhysicsWorld, s1.Body, s2.Body, Vector2.Zero, anchorB, 0.0f, 0.0f);
                        Joint.DampingRatio = 1.0f;
                        hookShot.HasAttached = true;
                        attached = true;
                        AttachedToWall = false;
                        retracting = true;
                        return true;
                    }
                }

                return false;
            }

            public override void Draw(SpriteBatch batch, WorldViewport viewport)
            {
                if(ropeTexture == null){
                    ropeTexture = World.ContentManager.Load<Texture2D>(@"SpriteTextures/HookShot/Rope");
                }
                Vector2 playerPos = World.CurrentLevel.Player.GetPosition();

                direction = World.CurrentLevel.Player.GetPosition() - GetPosition();
                length = direction.Length();

                Vector2 pos = playerPos + GetPosition();
                pos /= 2.0f;
                
                float angle = (float)Math.Atan2(direction.Y, direction.X);

                ropeSource.Width = (int)length;
               
                batch.Draw(
                    ropeTexture,
                    viewport.WorldToViewportCoords(pos),
                    ropeSource,
                    Color.White,
                    angle,
                    new Vector2(ropeSource.Center.X, ropeSource.Center.Y),
                    Scale,
                    SpriteEffects.None, 0);

                batch.Draw(
                    CurrentTexture,
                    viewport.WorldToViewportCoords(GetPosition()),
                    null,
                    Color.White,
                    GetRotation(),
                    GetCenter(),
                    Scale,
                    SpriteEffects.None, 0);
            }

            public void OnJointBreak(Joint j, float f)
            {
            }
        }
    }

}
